/*
 * Main.cpp
 *
 *  Created on: 2014. 7. 17.
 *      Author: mega@gamevil.com
 */

#include <mutex>
#include <condition_variable>

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

#include <Dispatcher/Static.h>
#include <Logger/Static.h>
#include <NoSQL/Static.h>
#include <Database/Static.h>

#include "Enum.h"
#include "Static.h"
#include "ListenHandler.h"
#include "GlobalChecker.h"
#include "NResource/Static.h"



//bool Init_Database()
//{
//	::Database::Session::Argument argument;
//	argument.nDatabaseType = 1;
//	argument.nCount = 1;
//	argument.strIP = ::ProjectZ::Config::Instance().GetResourceFile().host;
//	argument.strID = ::ProjectZ::Config::Instance().GetResourceFile().user;
//	argument.strPass = ::ProjectZ::Config::Instance().GetResourceFile().password;
//	argument.strDatabase = ::ProjectZ::Config::Instance().GetResourceFile().name;
//
//	bool bRet = ::Database::GETSESSION()->Open(argument);
//	if (false == bRet)
//	{
//		Log(ERR, "DATABASE OPEN FAIL");
//		return false;
//	}
//	else
//	{
//		Log(DEV, "DATABASE CONNECTED - ", argument.strDatabase.c_str(), ", ",argument.strIP.c_str(), ", ", argument.strID.c_str());
//	}
//
//	return true;
//}

bool init_Redis()
{
	Database::ResultSet res = Database::Execute(static_cast<int>(DatabaseType::GUILD_MASTER), "SELECT * FROM env_redis WHERE active = 1");
	if (0 != res.GetSQLError())
	{
		std::cerr << "env_redis query fail" << std::endl;
		return false;
	}

	if (res.end() == res.begin())
	{
		std::cerr << "env_redis query result is nothing" << std::endl;
		return false;
	}

//	::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
//	clsAuto->SetQueryType(::Database::Command::SELECT);
//	clsAuto->MakeQuery("SELECT * FROM env_redis WHERE active = 1 and type = %d", static_cast<int>(RedisServerType::GUILDRANK_MASTER) );
//	if (false == ::Database::GETSESSION()->SyncExecute(static_cast<int>(DatabaseType::GUILD_MASTER), clsAuto))
//		return false;
//
//	if( clsAuto->GetErrorIdx() != 0 )
//		return false;
//
//	if (0 == clsAuto->ResultRowCount())
//		return false;

	::Toolkit::Str<20> ip;
	::Toolkit::Str<50> desc;
	::Toolkit::Str<30> authKey;

	::NoSQL::Session::Info clsInfo;
	clsInfo._eServer	= ::NoSQL::Session::Info::REDIS;

	for(auto itr = res.begin(); itr != res.end(); itr++)
	{
		clsInfo.ip = itr->getString("ip").c_str();
		clsInfo._nServerType	= itr->getInt("type");
		clsInfo.port = itr->getInt("port");
		clsInfo.authKey = itr->getString("authkey").c_str();
	}

	LOG(DEV, __FUNCTION__, "> IP: ", clsInfo.ip.c_str(), ", port: ", clsInfo.port );

	if (false == ::NoSQL::SESSION()->RegistServer(1, clsInfo))
	{
		LOG(ERR, "false == ::NoSQL::SESSION()->RegistServer(1, clsInfo)");
		return false;
	}
	else
	{
		LOG(DEV, "CONNECTED REDIS> IP: ", clsInfo.ip.c_str(), ", port: ", clsInfo.port );
	}

	return true;
}


int main()
{
	std::mutex _mutex_;
	std::condition_variable _cond_;

	srand((unsigned)time(NULL));


    if (false == Logger::Init())
        return 0;

    Logger::SetLevelProperty(Logger::LOG_LEVEL_DEV, Logger::LOG_STDERR|Logger::LOG_FILE);
    Logger::SetLevelProperty(Logger::LOG_LEVEL_INF, Logger::LOG_STDERR|Logger::LOG_FILE);
    Logger::SetLevelProperty(Logger::LOG_LEVEL_ERR, Logger::LOG_STDERR|Logger::LOG_FILE|Logger::LOG_SYSLOG);

    // parse config
    boost::property_tree::ptree _ptree_;
    try {
    	boost::property_tree::xml_parser::read_xml("conf/GuildServer.xml", _ptree_);
    } catch (boost::exception & err) {
    	LOG(ERR, "Oops! Config Load Fail!");
    	return 0;
    }

//	::Dispatcher::Static dispatcher;
//	dispatcher.Init();
    if (false == Dispatcher::Init())
    {
    	LOG(ERR, "Fail Dispatcher Init");
    	return 0;
    }

//	::Database::Static clsDatabase;
//	clsDatabase.Init();

	::NoSQL::Static clsNoSQL;
	clsNoSQL.Init();

    if (false == Database::Init())
    {
    	LOG(ERR, "Fail Database Init");
    	return 0;
    }


    const char * host =  _ptree_.get<std::string>("server.database.connection.<xmlattr>.host").c_str();
	const char * id = _ptree_.get<std::string>("server.database.connection.<xmlattr>.user").c_str();
	const char * pass = _ptree_.get<std::string>("server.database.connection.<xmlattr>.passwd").c_str();
	const char * schema = _ptree_.get<std::string>("server.database.connection.<xmlattr>.db").c_str();

	if (false == Database::Connect(static_cast<int>(DatabaseType::GUILD_MASTER), host, 3306, id, pass, schema))
	{
    	LOG(ERR, "Fail Database Connect");
    	return 0;
	}

    ::GuildServer::NResource::Static	clsResourceStatic;
    if (false == clsResourceStatic.LoadResource())
    {
    	LOG(ERR, "Fail Resource Init");
    	return 0;
    }

    int listenPort = _ptree_.get<int>("server.session.<xmlattr>.port");
    LOG(INF, "Listen Port : ", listenPort);

    std::shared_ptr<GuildServer::ListenHandler> pListenHandler(new ::GuildServer::ListenHandler());
    if (false == Dispatcher::Listen(listenPort, pListenHandler.get(), 1024))
    {
    	LOG(ERR, "Fail Dispatcher Listen");
    	return 0;
    }

	if ( false == init_Redis() )
	{
		LOG(ERR, "init_Redis Fail");
		return 0;
	}

    ::GuildServer::Static clsStatic;
    clsStatic.LoadRecommendedGuilds();

    // 이전 랭킹/포인트 저장 테스트
    ::GuildServer::GuildRank& kRankList = ::GuildServer::Static::Instance().GetRankList();
    kRankList.PrintDailySnapshot();

    clsStatic.SetTest(_ptree_.get<int>("test.<xmlattr>.is_test"));

    LOG(DEV, "IsTest : ", clsStatic.GetTest());

    ::GuildServer::GlobalChecker clsChecker;



    LOG(INF, "[GUILD SERVER START]");

    std::unique_lock<std::mutex> lock(_mutex_);
    _cond_.wait(lock);

    return 0;
}
